/**
 * file		: regex.match.2.c
 * author	: John Saxon (09-Mar-2010)
 * revision	: $Rev: 5 $
 *
 * this program is to demonstrate how to use the POSIX regular
 * expression functions (defined in regex.h).
 *
 * this particular program shows you how to not only say whether
 * a string (argv[1]) is a match for a regular expression 
 * pattern (argv[2]); but allows to create backreferences.
 * a back reference stores the part of the string matched by the
 * regular expression inside round parentheses.
 */

#include <regex.h>
#include <stdio.h>
#include <string.h>

int 
main(int argc, char **argv)
{
	/**
	 * Usage: prog string regex 
	 * so should have 3 argsuments (inc. program name)
	 */
	if(argc == 3) /* so should have 3 argsuments (inc. program name) */
	{
		int status;
		/* compiled regex object (well not really an object ...) */
		regex_t regex;

		/* compile a regular expression */
		status = regcomp(&regex, argv[2], REG_EXTENDED);

		if(status == 0) /* success ? */
		{
			/* regex matches (+1 so to add a final object to it)*/
			regmatch_t matches[regex.re_nsub + 1];


			/* match the string to the regular expression */
			status = regexec(&regex, argv[1], regex.re_nsub + 1, matches, 0);
			/* output result */
			printf(
				"match: %c;\n",
				/* a bit of a ternary op here               *
				 * if(!failed) return 'y'; else return 'n'; */
				status != REG_NOMATCH ? 'y' : 'n'
			);

			/* does the regex have any backreferences *
			 * and did it match to the string         */
			if(regex.re_nsub > 0 && status != REG_NOMATCH)
			{
				int i; /* iterator */

				/* for each reference ... */
				for(i = 0; i <= regex.re_nsub; i++)
				{
					/* is this the last back reference? */
					if(matches[i].rm_so == -1)
						/* leave loop */
						break;
					else
					{
						/* get the length of the backreference */
						int length = matches[i].rm_eo - matches[i].rm_so;
						/* to store the string itself */
						char match[length];

						/* copy the substring from argv[1] */
						strncpy(
							match,
							argv[1] + matches[i].rm_so,
							length
						);
						
						/* add the trailing NULL */
						match[length] = '\0';

						/* print the match itself, with offsets */
						printf(
							"%d %d %s;\n",
							(int) matches[i].rm_so,
							(int) matches[i].rm_eo,
							match
						);
					}
				}
			}
		}
		else /* fail */
		{
			/* space for an error message */
			char err[50];

			/* get the error message */
			regerror(status, &regex, err, (size_t) sizeof(err));

			/* print the error message */
			printf("error: %s\n", err);
		}

		/* free the compiled regular expression */
		regfree(&regex);
	}
	/* called incorrectly */
	else
	{
		/* print usage */
		printf("Usage:\n\t%s str pattern\n", argv[0]);
	}

	return 0;
}
